#ifndef K_SOCKET_ACTION_H
#define K_SOCKET_ACTION_H
#pragma once

#include "KDef.h"
#include "KKey.h"

class KIAddress;
class KNetItem;
class KNetScene;
class KPackage;
class KStorage;

class KSocketAction : public KKey, protected KLockable {
protected:
    KSocketAction();
public:
    void abortOnce();
    void abortOnce(int reason);
protected:
    LONG errors(bool increase = true);
    KNetItem *item() const      { return m_item; }
    KNetScene *scene() const;
    KSocket *socket() const     { return m_sock; }
protected:
    // For both TCP and UDP
    bool postMessage(KKey *key = NULL);
    bool receive(size_t length = 0, KKey *key = NULL);
    // For TCP only
    bool send(KStorage *storage, size_t length = 0);
    bool send(const void *data, size_t length, KKey *key = NULL);
    bool transmit(HANDLE hFile, size_t length = 0, KKey *key = NULL, size_t blockLen = 0, KPackage *head = NULL, KPackage *tail = NULL);
    // For UDP only
    bool sendTo(const KIAddress &addrRemote, const void *data, size_t length, KKey *key = NULL);
protected:
    // For lifetime control
    void ensureAlive(bool always = true);
    KDef::Life lifeBegin();
    void lifeEnd(KDef::Life life);
protected:
    // Implementation
    virtual void abortImp();
    virtual void abortImp(int reason);
    // For TCP server only
    virtual void onAccepted(KSocket *client) {}
    virtual void onFatalError(KDef::SockError type, DWORD error) {}
    // For TCP only
    virtual void onConnected() {}
    virtual void onTransmitted(KKey *&key, HANDLE file, size_t length) {}
    // For UDP only
    virtual void onCreated() {}
    // For both TCP and UDP
    virtual void onClosing(bool stopped) {}
    virtual void onError(KDef::SockError type, DWORD error) {}
    virtual void onMessage(KKey *&key) {}
    virtual void onReceived(KKey *&key, void *data, size_t length, bool more) {}
    virtual void onSent(KKey *&key, void *data, size_t length) {}
    virtual void onSocketChanged() {}
private:
    void setItem(KNetItem *i)   { m_item = i; }
    void setSocket(KSocket *sock);
private:
    KNetItem *          m_item;
    KSocket *volatile   m_sock;
    volatile LONG       m_errors;
    friend class        KNetItem;
};

#endif // K_SOCKET_ACTION_H